package com.xiaotu.code.system;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.TaskExecutor;

/**
 * 任务工厂.
 * 
 * 用户将同步任务、非同步任务加入线程池中执行.
 * 
 * @author chenxiagnrong
 * 
 */
public class TaskFactory implements Serializable, BeanFactoryAware, InitializingBean, DisposableBean {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2578039367226387007L;
	protected final Logger logger = LoggerFactory.getLogger(getClass());
	// bean工厂，可能任务中需要用到service，通过bean工厂能获取到service
	private BeanFactory beanFactory;
	// 任务管理器.
	private TaskExecutor taskExec;
	// 当前工厂线程
	private TastFacotryRunner runner = null;

	/**
	 * 加入任务到任务工厂线程池中.
	 * 
	 * @param task
	 */
	public void addTask(BaseTask task) {

		try {
			logger.info("添加新任务" + task.getTaskName());
			task.setBeanFactory(beanFactory);
			// 如果是并发的任务，需要加入并发队列
			if (task.isSync()) {
				runner.addSyncTask(task);
			} else {
				// 非并发队列，直接运行
				this.taskExec.execute(new SimpleTaskWrap(task));
			}
		} catch (Exception e) {
			logger.error("任务执行错误" + task.getTaskName(), e);
		}
	}

	/**
	 * 启动线程.
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		runner = new TastFacotryRunner(this);
		runner.start();
	}

	/**
	 * 关闭线程.
	 */
	@Override
	public void destroy() throws Exception {
		runner.destroy();
	}

	/**
	 * 内部类，顺序执行需要同步的任务.
	 * 
	 * @author liqinghua
	 * 
	 */
	private class TastFacotryRunner extends Thread {

		private TaskFactory factory;
		// 任务同步锁
		private Map<String, Date> lockContainer = new HashMap<String, Date>();
		// 同步任务容器
		private List<BaseTask> syncTaskContainer = new ArrayList<BaseTask>();
		// 当前工厂线程是否运行
		private boolean isRuning = true;

		public TastFacotryRunner(TaskFactory factory) {
			super();
			this.factory = factory;
		}

		@Override
		public void run() {

			while (isRuning) {

				// 如果当前没有待运行的任务，则进入阻塞
				if (syncTaskContainer.size() <= 0) {
					try {
						synchronized (this) {
							this.wait();
						}
					} catch (InterruptedException e) {
						logger.error("wait error", e);
					}
				} else {

					// 遍历是否有能够运行的任务
					for (int i = 0; i < syncTaskContainer.size();) {
						BaseTask task = syncTaskContainer.get(i);
						if (task == null) {
							syncTaskContainer.remove(i);
							continue;
						}
						// 是否配置延迟，如果延迟，则让出位置
						Date now = new Date();
						if (now.getTime() - task.getJoinTime().getTime() < task.getDelay() * 1000) {
							i++;
							continue;
						}
						Date pastTime = lockContainer.get(task.getTaskName());
						// 是否过期，不过期的话加入线程池执行
						if (pastTime == null || pastTime.after(now)) {
							syncTaskContainer.remove(i);
							Calendar cal = Calendar.getInstance();
							// 最多执行到10秒后
							cal.add(Calendar.SECOND, 10);
							lockContainer.put(task.getTaskName(), cal.getTime());
							SyncTaskWrap syncWrap = new SyncTaskWrap(lockContainer, task);
							factory.getTaskExec().execute(syncWrap);
						} else {
							i++;
						}
					}
					// 遍历完成后，休眠0.5秒
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						logger.error("sleep error", e);
					}
				}
			}
		}

		/**
		 * 加入同步任务到同步任务池.
		 * 
		 * @param task
		 */
		public synchronized void addSyncTask(BaseTask task) {

			this.syncTaskContainer.add(task);
			// 唤醒阻塞
			synchronized (this) {
				this.notify();
			}
		}

		/**
		 * bean销毁的时候，将线程关闭.
		 */
		public void destroy() {
			this.isRuning = false;
			// 唤醒阻塞
			synchronized (this) {
				this.notify();
			}
		}
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

		this.beanFactory = beanFactory;
	}

	public TaskExecutor getTaskExec() {
		return taskExec;
	}

	/**
	 * 线程池.
	 * 
	 * @param taskExec
	 */
	public void setTaskExec(TaskExecutor taskExec) {
		this.taskExec = taskExec;
	}
}
